/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package compilador.AnalisadorSintatico;

import compilador.AnalisadorLexico.Atomo;
import compilador.AnalisadorLexico.Atomo.TokenType;
import compilador.AnalisadorSemantico.GeracaoDeCodigo.TiposAS;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Leles
 */
public class SubMaquina {
    // Static items: used by sub-classes to create the decision tables
    int numEstados;
    int numAtomos;
    Transicao [][] Tabela_Decisao;
    int estadoInicial;
    int estadoFinal;
    
    private int NumeroEstrutura;
    
    private boolean brakable;
    private String lastBrakableScope;
    
    public Atomo run (Atomo CarriedToken){
        Atomo at;
        Transicao trans;
        
        NumeroEstrutura =  ++ Sintatico.sem.Cod.labelCount;
        
        
        boolean carryUsed = true;
        if (CarriedToken != null)
            carryUsed = false;
        
        int estado = estadoInicial;
        
        do{
            // DEBUG
            //System.out.println(this.getClass());
            try {
                if (carryUsed == false){
                    at = CarriedToken;
                    carryUsed = true;
                }
                else
                    at = Sintatico.lex.ProximoAtomo();
            }
            catch (RuntimeException e) {
                   //System.out.println("Exception e: " + e.getMessage());
                   throw e;
            }

            
            trans = Tabela_Decisao [estado][at.tipo.ordinal()];
            
            if (trans==null){
                
                trans = Tabela_Decisao [estado][Atomo.TokenType.TRANSICAO_VAZIA.ordinal()];
                
                if (trans==null){
                    // Dar um mega chilique (uuuuiiiii) aqui!!
                    // Rodar uma função que procura os atomos esperados! (estaile)
                    // throw new RuntimeException ("\n\nErro sintatico!\nAprenda a programar!!!");
                    String SErr = "\n\nErro sintatico!" +
                                  "\n" + Sintatico.lex.getPosicaoCodigo() +
                                  "\n Esperado(s): " + tokensEsperados(estado);
                    System.out.println(SErr);
                    throw new RuntimeException(SErr);
                }
                
                if (trans.estado == estadoFinal)
                    return at;
            }
            
            
            if (trans.acaoSemantica != TiposAS.ACAO_NENHUMA) {
                Sintatico.sem.Cod.AcaoSemantica(trans.acaoSemantica, NumeroEstrutura, at.valor, this);
            }
            
            
            if (trans.tipo == Transicao.TipoTransicao.Estado){
                estado = trans.estado;
            }
            else if (trans.tipo == Transicao.TipoTransicao.SubMaquina){
                SubMaquina S = null;
                try {
                    S = (SubMaquina) trans.submaquina.newInstance();
                } catch (InstantiationException ex) {
                    Logger.getLogger(SubMaquina.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(SubMaquina.class.getName()).log(Level.SEVERE, null, ex);
                }
                
                try { CarriedToken =  S.run(at); }
                catch (RuntimeException e) {
                    throw e;
                }
                    
                if (CarriedToken != null)
                    carryUsed = false;
                
                estado = trans.estado;
            }
            else
                throw new RuntimeException("Erro sintatico nao tratado!!!");
        
            
        
        }
        while (estado != estadoFinal);
                    
        
        
        return null;
    }
    
    private String tokensEsperados (int estado){
        
        String S = new String();
        int i;
        
        for (i=0; i<numAtomos; i++){
            if (Tabela_Decisao[estado][i] != null){
                if (! S.equals(""))
                    S = S + ", ";
                S = S + TokenType.values()[i];
            }
        }
        
        return S;
    }
    
}
